using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Campus
{
    public enum MoveDirection { Up, Down, Left, Right };

    public class Sprite
    {

        #region Type Definitions
        /// <summary>
        /// The delegate function signature that is used for the collisionAction field
        /// <param name="sprite1">one sprite that is colliding</param>
        /// <param name="sprite2">the other sprite that is colliding</param>
        /// </summary>
        public delegate void collisionActionDelegate(Sprite sprite1, Sprite sprite2);
        #endregion

        #region All the Fields and their getters/setters

        /// <summary>
        /// The sprite's texture (since many Sprites can share a texture, make sure that this only gets used as a reference)
        /// </summary>
        private Texture2D m_texture = null;
        public Texture2D Texture
        {
            get { return m_texture; }
            set { m_texture = value; }
        }

        /// <summary>
        /// The upper-left corner of the sprite
        /// </summary>
        private Vector2 m_position = new Vector2(0, 0);
        public Vector2 Position
        {
            get { return m_position; }
            set { m_position = value; }
        }

        /// <summary>
        /// The velocity of the sprite
        /// </summary>
        private Vector2 m_velocity = new Vector2(0, 0);
        public Vector2 Velocity
        {
            get { return m_velocity; }
            set { m_velocity = value; }
        }

        /// <summary>
        /// How much to adjust Sprite velocity when a movement key is pressed
        /// 
        /// TODO: Resolve incongruity between Sprite's moveSpeed, Unit's moveSpeed, and Projectile's moveSpeed.  It's an issue because they're used independently of each other.
        /// </summary>
        private float moveSpeed = 0.0f;
        public float m_moveSpeed
        {
            get { return moveSpeed; }
            set { moveSpeed = value; }
        }

        /// <summary>
        /// How large the Sprite will be drawn
        /// </summary>
        private Vector2 m_size = new Vector2(40, 40);
        public Vector2 Size
        {
            get { return m_size; }
            set { m_size = value; }
        }

        /// <summary>
        /// The maximum speed the Sprite can attain
        /// </summary>
        private Vector2 m_maxSpeed = new Vector2(0, 0);
        public Vector2 MaxSpeed
        {
            get { return m_maxSpeed; }
            set { m_maxSpeed = value; }
        }

        /// <summary>
        /// Used for calculating collisions
        /// </summary>
        private float m_mass = 1.0f;
        public float Mass
        {
            get { return m_mass; }
            set { m_mass = value; }
        }

        /// <summary>
        /// Whether or not to draw the Sprite when the draw function is called.
        /// </summary>
        private bool m_isVisible = true;
        public bool IsVisible
        {
            get { return m_isVisible; }
            set { m_isVisible = value; }
        }

        /// <summary>
        /// The portion of the texture that should be drawn at the position (with the Sprite's size)
        /// </summary>
        private Rectangle m_visiblePartOfTexture = new Rectangle(0, 0, 0, 0);
        public Rectangle VisiblePartOfTexture
        {
            get { return m_visiblePartOfTexture; }
            set { m_visiblePartOfTexture = value; }
        }

        /// <summary>
        /// Cumulative force on the Sprite (no need to keep track of collection...just the cumulative vector)
        /// </summary>
        private Vector2 m_forces = new Vector2(0, 0);
        public Vector2 Forces
        {
            get { return m_forces; }
            set { m_forces = value; }
        }

        /// <summary>
        /// The color to draw the Sprite.  Careful...the fourth parameter to Color is the opacity!
        /// </summary>
        private Color m_color = Color.White;
        public Color Color
        {
            get { return m_color; }
            set { m_color = value; }
        }
        /// <summary>
        /// The opacity of the Sprite
        /// </summary>
        public byte Opacity
        {
            get { return m_color.A; }
            set { m_color = new Color(m_color.R, m_color.G, m_color.B, value); }
        }

        /// <summary>
        /// The angle, in radians, to rotate the sprite around the origin
        /// </summary>
        private float m_rotation = 0.0f;
        public float Rotation
        {
            get { return m_rotation; }
            set { m_rotation = value; }
        }

        /// <summary>
        /// When drawn at (0,0), the point in the Sprite which will occupy the (0,0)th pixel.
        /// </summary>
        public Vector2 Origin
        {
            get { return m_origin; }
            set { m_origin = value; }
        }
        private Vector2 m_origin = Vector2.Zero;

        /// <summary>
        /// The z value given to this Sprite when drawn (0.0 = closest, 1.0 = furthest).
        /// </summary>
        public float LayerDepth
        {
            get { return m_layerDepth; }
        }
        private float m_layerDepth = 0.0f;

        /// <summary>
        /// Sprite Effects to be applied to the Sprite when drawn.
        /// </summary>
        public SpriteEffects Effects
        {
            get { return m_effects; }
        }
        private SpriteEffects m_effects = SpriteEffects.None;

        /// <summary>
        /// The bounding box with which to do collisions
        /// </summary>
        private BoundingSphere m_boundingSphere = new BoundingSphere(Vector3.Zero, 0.0f);
        public BoundingSphere BoundingSphere
        {
            get { return m_boundingSphere; }
            set { m_boundingSphere = value; }
        }

        /// <summary>
        /// The function that will get called when doCollision is called
        /// </summary>
        private collisionActionDelegate m_collisionAction = null;
        public collisionActionDelegate CollisionAction
        {
            set { m_collisionAction = value; }
        }

        /// <summary>
        /// The InputHandler that will contain the default keys for moving a Sprite.
        /// (i.e. up, down, left, right)
        /// </summary>
        protected InputHandler m_inputHandler;

        private Animation m_currentAnimation;
        public Animation CurrentAnimation
        {
            get { return m_currentAnimation; }
            set { m_currentAnimation = value; }
        }
        private TextureMapAnimation m_currentMapAnimation;
        public TextureMapAnimation CurrentMapAnimation
        {
            get { return m_currentMapAnimation; }
            set { m_currentMapAnimation = value; }
        }

        #endregion

        #region Constructors
        public Sprite(Texture2D texture, Vector2 position)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed, float mass)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_mass = mass;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed, float mass, float m_rotation)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_mass = mass;
            this.m_rotation = m_rotation;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed, float mass, float m_rotation, Color color)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_mass = mass;
            this.m_rotation = m_rotation;
            this.m_color = color;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed, float mass, float m_rotation, Color color,
            Vector2 forces)
        {
            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_mass = mass;
            this.m_rotation = m_rotation;
            this.m_color = color;
            this.m_forces = forces;
            this.m_visiblePartOfTexture = new Rectangle();
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Texture2D texture, Vector2 position, Vector2 velocity, collisionActionDelegate collisionAction,
            Vector2 size, Vector2 maxSpeed, float mass, float m_rotation, Color color,
            Vector2 forces, Rectangle visiblePartOfTexture)
        {

            this.m_texture = texture;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_collisionAction = collisionAction;
            this.m_size = size;
            this.m_maxSpeed = maxSpeed;
            this.m_mass = mass;
            this.m_rotation = m_rotation;
            this.m_color = color;
            this.m_forces = forces;
            this.m_visiblePartOfTexture = visiblePartOfTexture;
            this.m_inputHandler = new InputHandler();
        }
        // -------------------------CONSTRUCTORS FOR ANIMATIONS--------------------------
        public Sprite(Animation animation, Vector2 position)
        {
            m_currentAnimation = animation;
            this.m_position = position;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(Animation animation, Vector2 position, Vector2 velocity)
        {
            m_currentAnimation = animation;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(TextureMapAnimation animation, Vector2 position)
        {
            m_currentMapAnimation = animation;
            this.m_position = position;
            this.m_inputHandler = new InputHandler();
        }
        public Sprite(TextureMapAnimation animation, Vector2 position, Vector2 velocity)
        {
            m_currentMapAnimation = animation;
            this.m_position = position;
            this.m_velocity = velocity;
            this.m_inputHandler = new InputHandler();
        }
        
        /// <summary>
        /// Creates a Sprite object from the parts necessary to draw a Sprite to the screen.
        /// </summary>
        /// <param name="texture">The texture to be used for drawing this Sprite object.</param>
        /// <param name="drawSize">The size (in pixels) of the area into which to draw this Sprite.</param>
        /// <param name="origin">When drawn at (0,0), the point in the Sprite which will occupy the (0,0)th pixel.</param>
        /// <param name="color">The color to tint this Sprite when it is drawn.</param>
        /// <param name="effects">Sprite Effects to be applied to the Sprite when drawn.</param>
        /// <param name="layerDepth">The z value given to this Sprite when it gets drawn (0.0 = closest, 1.0 = furthest).</param>
        public Sprite(Texture2D texture, Vector2 position, Vector2 drawSize, Vector2 origin, Color color, SpriteEffects effects, float layerDepth, collisionActionDelegate collisionAction)
        {
            m_texture = texture;
            m_position = position;
            m_size = drawSize;
            m_origin = origin;
            m_color = color;
            m_effects = effects;
            m_layerDepth = layerDepth;
            m_collisionAction = collisionAction;
        }
        #endregion

        #region All other Functions
        /// <summary>
        /// Draws the visible portion of the sprite's texture at its position, with its size, color, and rotation
        /// </summary>
        public void Draw(SpriteBatch spriteBatch)
        {
            //spriteBatch.Draw(texture, new Rectangle(, , (int)size.X, (int)size.Y), visiblePartOfTexture, color, rotation, new Vector2(size.X / 2, size.Y / 2), SpriteEffects.None, 0);
            if (m_currentMapAnimation == null)
            {
                spriteBatch.Draw(m_texture, new Rectangle((int)m_position.X, (int)m_position.Y, (int)(m_size.X), (int)(m_size.Y)), m_visiblePartOfTexture, m_color, m_rotation, new Vector2(m_size.X / 2, m_size.Y / 2), SpriteEffects.None, 0);
            }
            else
            {
                int magicGoldMine = m_currentMapAnimation.Index / m_currentMapAnimation.Map.Cols;
                int currentCol = m_currentMapAnimation.Index % m_currentMapAnimation.Map.Cols;

                int imageWidth = m_currentMapAnimation.Map.Width;
                int imageHeight = m_currentMapAnimation.Map.Height;

                Rectangle source = new Rectangle(currentCol * imageWidth, magicGoldMine * imageHeight, imageWidth, imageHeight);
                Rectangle dest = new Rectangle((int)m_position.X, (int)m_position.Y, imageWidth, imageHeight);

                spriteBatch.Draw(m_currentMapAnimation.Map.Image, dest, source, Color.White);
            }
            //spriteBatch.Draw(this.texture, new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y),
            //null, Color.White, rotation, size / 2, SpriteEffects.None, 0.0f);
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// Adds the given force vector to the current force vector of the Sprite
        /// </summary>
        public void AddForce(Vector2 force)
        {
            this.m_forces = m_forces + force;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// Updates the sprite by adding the forces to the velocity vector and then moving the sprite
        /// </summary>
        virtual public void Update(GameTime gameTime, bool checkInput, bool updateBoundingBox)
        {
            if (checkInput)
            {
                this.CheckInput();
            }
            m_velocity += (m_forces / (float)m_mass * (float)gameTime.ElapsedGameTime.TotalSeconds);
            float velocityMagnitude = (float)Math.Sqrt(m_velocity.X * m_velocity.X + m_velocity.Y * m_velocity.Y);
            if (velocityMagnitude > m_maxSpeed.Length())
            {
                m_velocity.X = m_maxSpeed.X * (m_velocity.X / velocityMagnitude);
                m_velocity.Y = m_maxSpeed.Y * (m_velocity.Y / velocityMagnitude);
            }
            m_position += m_velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (updateBoundingBox)
            {
                UpdateBoundingSphere();
            }
            // Updates the current texture to the Animation's current Texture, if the Sprite was given
            // an Animation object in the constructor.
            if (m_currentAnimation != null)
            {
                m_currentAnimation.Update(gameTime);
                Texture = m_currentAnimation.CurrentTexture;
            }
        }

        /// <summary>
        /// Determines if this Sprite collides with the given Bounding Box
        /// </summary>
        public bool CollidesWith(BoundingSphere otherSphere)
        {
            // ContainmentType.Disjoint means that otherSphere is neither overlapped nor contained.
            return m_boundingSphere.Contains(otherSphere) != ContainmentType.Disjoint;
        }

        /// <summary>
        /// Updates the bounding box to cover the Sprite (given its position and size).
        /// </summary>
        public void UpdateBoundingSphere()
        {
            // Get references for calculating where we want the sphere to be.
            float yReference = m_size.Y / 4;
            float xReference = m_size.X / 2;

            // Set the center to be 3/4 of the way down the sprite and 1/2 way across.
            Vector3 center = new Vector3(m_position.X - m_origin.X + xReference, m_position.Y - m_origin.Y + (yReference * 3), 0.0f);
            // Set the radius to be the min of .5x and .25y so it only extends to the end of the sprite in one direction.
            float radius = Math.Min(xReference, yReference);
            // Set the radius to be the average of the x and y references to it (hopefully) strikes a good midpoint.
            //float radius = (xReference + yReference) / 2;

            m_boundingSphere = new BoundingSphere(center, radius);
        }

        /// <summary>
        /// Function to call to perform the collision action
        /// </summary>
        public void DoCollision(Sprite sprite1, Sprite sprite2)
        {
            m_collisionAction(sprite1, sprite2);
        }

        /// <summary>
        /// Goes through and sees if the assigned buttons are being pressed.
        /// </summary>
        public void CheckInput()
        {
            m_inputHandler.CheckInputs();
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// Moves the Sprite by the given x and y offsets.
        /// <param name="offset">The vector containing the x and y offsets.</param>
        /// </summary>
        public void Move(Vector2 offset)
        {
            m_position += offset;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// This function should be bound in the input handler to whatever button should move 
        /// the Sprite up(i.e. up arrow).  It will then be called when the button is activated.
        /// <param name="state">The state of the button (pressed or released)</param>
        /// </summary>
        private void MoveUp(Keys key, KeyState state)
        {
            this.m_velocity.Y -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveUp(Buttons button, ButtonState state, PlayerIndex index)
        {
            this.m_velocity.Y -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveUp(MouseButtons button, ButtonState state)
        {
            this.m_velocity.Y -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// This function should be bound in the input handler to whatever button should move 
        /// the Sprite down(i.e. down arrow).  It will then be called when the button is activated.
        /// <param name="state">The state of the button (pressed or released)</param>
        /// </summary>
        private void MoveDown(Buttons button, ButtonState state, PlayerIndex index)
        {
            this.m_velocity.Y += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveDown(Keys key, KeyState state)
        {
            this.m_velocity.Y += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveDown(MouseButtons button, ButtonState state)
        {
            this.m_velocity.Y += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// This function should be bound in the input handler to whatever button should move 
        /// the Sprite left(i.e. left arrow).  It will then be called when the button is activated.
        /// <param name="state">The state of the button (pressed or released)</param>
        /// </summary>
        private void MoveLeft(Buttons button, ButtonState state, PlayerIndex index)
        {
            this.m_velocity.X -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveLeft(Keys key, KeyState state)
        {
            this.m_velocity.X -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveLeft(MouseButtons button, ButtonState state)
        {
            this.m_velocity.X -= this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// This function should be bound in the input handler to whatever button should move 
        /// the Sprite right(i.e. right arrow).  It will then be called when the button is activated.
        /// <param name="state">The state of the button (pressed or released)</param>
        /// </summary>
        private void MoveRight(Buttons button, ButtonState state, PlayerIndex index)
        {
            this.m_velocity.X += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveRight(Keys key, KeyState state)
        {
            this.m_velocity.X += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        private void MoveRight(MouseButtons button, ButtonState state)
        {
            this.m_velocity.X += this.moveSpeed;
            //throw new System.NotImplementedException();
        }

        /// <summary>
        /// Assigns the given button to the given direction of movement.
        /// </summary>
        public void AssignButtonToMovement(Keys keyboardButton, MoveDirection direction)
        {
            // Make sure to check that m_inputHandler is initialized before trying to add to it.
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Bind(keyboardButton, MoveUp, 0);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Bind(keyboardButton, MoveDown, 0);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Bind(keyboardButton, MoveLeft, 0);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Bind(keyboardButton, MoveRight, 0);
                        break;
                }
            }
            //throw new System.NotImplementedException();
        }
        public void AssignButtonToMovement(Buttons gamePadButton, MoveDirection direction)
        {
            // Make sure to check that m_inputHandler is initialized before trying to add to it.
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Bind(gamePadButton, MoveUp, 0);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Bind(gamePadButton, MoveDown, 0);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Bind(gamePadButton, MoveLeft, 0);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Bind(gamePadButton, MoveRight, 0);
                        break;
                }
            }

            //throw new System.NotImplementedException();
        }
        public void AssignButtonToMovement(MouseButtons mouseButton, MoveDirection direction)
        {
            // Make sure to check that m_inputHandler is initialized before trying to add to it.
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Bind(mouseButton, MoveUp, 0);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Bind(mouseButton, MoveDown, 0);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Bind(mouseButton, MoveLeft, 0);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Bind(mouseButton, MoveRight, 0);
                        break;
                }
            }

            //throw new System.NotImplementedException();
        }
        /// <summary>
        /// Removes the given button from the given direction of movement
        /// </summary>
        public void RemoveButtonFromMovement(Keys keyboardButton, MoveDirection direction)
        {
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Unbind(keyboardButton, MoveUp);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Unbind(keyboardButton, MoveDown);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Unbind(keyboardButton, MoveLeft);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Unbind(keyboardButton, MoveRight);
                        break;
                }
            }
            //throw new System.NotImplementedException();
        }
        public void RemoveButtonFromMovement(Buttons gamePadButton, MoveDirection direction)
        {
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Unbind(gamePadButton, MoveUp);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Unbind(gamePadButton, MoveDown);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Unbind(gamePadButton, MoveLeft);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Unbind(gamePadButton, MoveRight);
                        break;
                }
            }
            //throw new System.NotImplementedException();
        }
        public void RemoveButtonFromMovement(MouseButtons mouseButton, MoveDirection direction)
        {
            if (m_inputHandler != null)
            {
                switch (direction)
                {
                    case (MoveDirection)0:
                        m_inputHandler.Unbind(mouseButton, MoveUp);
                        break;

                    case (MoveDirection)1:
                        m_inputHandler.Unbind(mouseButton, MoveDown);
                        break;

                    case (MoveDirection)2:
                        m_inputHandler.Unbind(mouseButton, MoveLeft);
                        break;

                    case (MoveDirection)3:
                        m_inputHandler.Unbind(mouseButton, MoveRight);
                        break;
                }
            }

            //throw new System.NotImplementedException();
        }
        // This method should be called so that Sprite can dynamically choose how to
        // draw the sprite.  This method takes in a Rectangle for the destination
        public void Draw(SpriteBatch spriteBatch, Rectangle destRect)
        {
            if (m_currentMapAnimation == null)
            {
                spriteBatch.Draw(m_texture, destRect, m_visiblePartOfTexture, m_color, m_rotation, new Vector2(m_size.X / 2, m_size.Y / 2), SpriteEffects.None, 0);
            }
            else
            {
                int currentRow = m_currentMapAnimation.Index / m_currentMapAnimation.Map.Cols;
                int currentCol = m_currentMapAnimation.Index % m_currentMapAnimation.Map.Cols;

                int imageWidth = m_currentMapAnimation.Map.Width;
                int imageHeight = m_currentMapAnimation.Map.Height;

                Rectangle source = new Rectangle(currentCol * imageWidth, currentRow * imageHeight, imageWidth, imageHeight);

                spriteBatch.Draw(m_currentMapAnimation.Map.Image, destRect, source, Color.White);
            }
        }
        #endregion
    }
}